package com.hk.core.data.r2dbc.repository;

import com.hk.commons.query.Order;
import com.hk.commons.query.page.QueryPage;
import com.hk.core.data.r2dbc.repository.support.R2dbcRepositorySupport;
import com.hk.core.jdbc.SelectArguments;
import com.hk.core.jdbc.query.Condition;
import com.hk.core.jdbc.query.ConditionQueryModel;
import com.hk.core.jdbc.query.Parametric;
import org.springframework.data.domain.Persistable;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.repository.support.SimpleR2dbcRepository;
import org.springframework.data.relational.repository.query.RelationalEntityInformation;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

/**
 * @author Kevin
 */
public class BaseSimpleR2dbcRepository<T extends Persistable<ID>, ID extends Serializable>
        extends SimpleR2dbcRepository<T, ID>
        implements BaseR2dbcRepository<T, ID> {

    private final RelationalEntityInformation<T, ID> entity;

    public BaseSimpleR2dbcRepository(RelationalEntityInformation<T, ID> entity,
                                     R2dbcEntityOperations entityOperations,
                                     R2dbcConverter converter) {
        super(entity, entityOperations, converter);
        this.entity = entity;
    }

    public BaseSimpleR2dbcRepository(RelationalEntityInformation<T, ID> entity,
                                     DatabaseClient databaseClient,
                                     R2dbcConverter converter,
                                     ReactiveDataAccessStrategy accessStrategy) {
        super(entity, databaseClient, converter, accessStrategy);
        this.entity = entity;
    }

    @Override
    public Mono<QueryPage<T>> queryForPage(ConditionQueryModel queryModel) {
        var arguments = SelectArguments.newSelectArguments(queryModel);
        arguments.setParametric(Parametric.PARAMETERIZATION);
        arguments.setConditions(queryModel.getParam());
        arguments.setFrom(entity.getTableName().getReference());
        return R2dbcRepositorySupport.queryForPage(arguments, entity.getJavaType());
    }

    @Override
    public Flux<T> findAll(List<Condition> conditions, Order... orders) {
        var arguments = new SelectArguments();
        arguments.setParametric(Parametric.PARAMETERIZATION);
        arguments.getConditions().addConditions(conditions);
        arguments.setOrders(List.of(orders));
        arguments.setFrom(entity.getTableName().getReference());
        return R2dbcRepositorySupport.queryForList(arguments, entity.getJavaType());
    }

    @Override
    public Mono<T> findById(ID id) {
        return Objects.isNull(id) ? Mono.empty() : super.findById(id);
    }

    @Override
    public Mono<Boolean> existsById(ID id) {
        return Objects.isNull(id) ? Mono.just(false) : super.existsById(id);
    }
}
